/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/

/**
 * 和sw4核 vcan相关功能函数
 */
#include <stdarg.h>
#include <stdio.h>
#include "eth2can.h"  // 里面有TCM内存区域的定义
#include "can_config.h"
#include "route.h"
#include "can_output.h"
#include "VCan_Command.h"
#include "VCan_Types.h"
#include "vcan.h"

extern switch0_can_gateway_ipc_server_t *can_s_server;

// vcan msgbox回调函数声明
static int vcan_cb_init_done(uint32_t param);
static int vcan_cb_set_controller(uint32_t param);
static int vcan_cb_init_base_route_table(uint32_t param);
static int vcan_cb_init_common_route_table(uint32_t param);
static int vcan_cb_set_route_table(uint32_t param);
static int vcan_cb_send_data(uint32_t param);

// 函数指针类型定义和命令函数映射表
typedef int (*LLCG_COMMAND_FUNCTION)(uint32_t param);
typedef struct vcan {
    LLCG_COMMAND_ENUM command;
    LLCG_COMMAND_FUNCTION func;
} VCAN_COMMAND_FUNCTION_MAP_BASE;

static VCAN_COMMAND_FUNCTION_MAP_BASE command_function_map[] = {
    {LLCG_COMMAND_INIT_DONE, vcan_cb_init_done},
    {LLCG_COMMAND_SET_CONTROLLER, vcan_cb_set_controller},
    {LLCG_COMMAND_INIT_BASE_ROUTE_TABLE, vcan_cb_init_base_route_table},
    {LLCG_COMMAND_INIT_COMMON_ROUTE_TABLE, vcan_cb_init_common_route_table},
    {LLCG_COMMAND_SET_ROUTE_TABLE, vcan_cb_set_route_table},
    {LLCG_COMMAND_SET_ROUTE_TABLE, vcan_cb_set_route_table}
};
static int command_function_map_len = (sizeof(command_function_map) / sizeof(command_function_map[0]));

static LLCG_RouteTableBaseType* origin_base_route_ptr = NULL;  // SW4传递下来的原始路由表指针

/**
 * @brief vcan_subcribed表示哪些核向vcan订阅。 当vcan收到消息后，会向这些核发送一个ipc通知
 *        例如：vcan_subcribed[1]==1 代表SWITCH1核向VCAN核订阅了通知
 *              vcan_subcribed[4]==1 代表ADAS核向VCAN核订阅了通知
 *        具体的索引规则请见 route_destination_to_ipc_cpu_map 变量。
*/
uint8 vcan_subcribed[VCAN_MAX_SUBCRIBED] = {0};    
broadcast_reg_entry_t vcan_subcribed_info[VCAN_MAX_SUBCRIBED] = {0};

/**
 * @brief sw0核收到sw4核的msgbox消息回调
 */
void vcan_method_callback(uint8_t command, uint32_t param,
                          uint64_t context, const ext_info_t *info)
{
    int ret=-1;
    switch0_can_gateway_ErrorEnum_t reply = SWITCH0_CAN_GATEWAY_NO_ERROR;

    for (int i = 0; i < command_function_map_len; ++i) {
        if (command == command_function_map[i].command) {
            if (command_function_map[i].func != NULL) {
                ret = command_function_map[i].func(param);
            } 
			else {
                hprintf(DEBUG, "vcan_method_callback find command, but cb func is null!\n");
            }
            break;
        }
    }

    if (ret != 0) {
        hprintf(DEBUG, "vcan_method_callback cb func ret is not 0\n");
        reply = SWITCH0_CAN_GATEWAY_SERVER_FAIL;
    }

    can_s_server->switch0_can_gateway_server.reply_vcan_method(reply, context);
}

/**
 * vcan_cb_init_done
 * @brief: 暂时弃用
*/
static int vcan_cb_init_done(uint32_t param) {
    hprintf(DEBUG, "receive msgbox vcan_cb_init_done param:0x%x\n", param);
    return 0;
}


/**
 * vcan_cb_set_controller
 * @brief: SW4核下发controller设置OK，SW0核可以开始轮询了
*/
static int vcan_cb_set_controller(uint32_t param) {
    LLCG_COMMAND_PARAM_SET_CONTROLLER *converted_param = (LLCG_COMMAND_PARAM_SET_CONTROLLER*)param;
    can_forward_port_init(converted_param->can_controller_id);
    return 0;
}

/**
 * vcan_cb_init_base_route_table
 * @brief: SW4核下发路由表信息，SW0核负责拷贝一份到本地
*/
static int vcan_cb_init_base_route_table(uint32_t param) {
    LLCG_COMMAND_PARAM_INIT_BASE_ROUTE_TABLE *converted_param = (LLCG_COMMAND_PARAM_INIT_BASE_ROUTE_TABLE*)param;

    LLCG_RouteTableBaseType *base_route_table_ptr = (LLCG_RouteTableBaseType*)converted_param->base_route_table_ptr;
    uint32_t base_route_table_size = converted_param->base_route_table_size;

    // 检查路由表长度有没有超过限制
    if (base_route_table_size > VCAN_BASE_ROUTE_TABLE_SIZE) {
        hprintf(DEBUG, "error: base_route_table_size over MAXSIZE:%d Byte\n", VCAN_BASE_ROUTE_TABLE_SIZE);
        return -1;
    }

    can_base_route_table_set(base_route_table_ptr, base_route_table_size / sizeof(LLCG_RouteTableBaseType));
    // 设置对应的全局变量
    origin_base_route_ptr = base_route_table_ptr;

    return 0;
}

/**
 * vcan_cb_init_common_route_table
 * @brief: SW4核下发路由表信息，SW0核负责拷贝一份到本地
*/
static int vcan_cb_init_common_route_table(uint32_t param) {
    LLCG_COMMAND_PARAM_INIT_COMMON_ROUTE_TABLE *converted_param = (LLCG_COMMAND_PARAM_INIT_COMMON_ROUTE_TABLE*)param;

    uint8_t can_controller_id = converted_param->can_controller_id;
    LLCG_CommonRouteTableType *common_route_table_ptr = (LLCG_CommonRouteTableType *)converted_param->common_route_table_ptr;
    uint32_t common_route_table_size = converted_param->common_route_table_size;

    if (common_route_table_size > VCAN_COMMON_ROUTE_TABLE_SIZE_EACH_CONTROLLER) {
        hprintf(DEBUG, "error: common_route_table_size over MAXSIZE:%d Byte\n", VCAN_COMMON_ROUTE_TABLE_SIZE_EACH_CONTROLLER);
        return -1;
    }

    can_common_route_table_set(can_controller_id, common_route_table_ptr, common_route_table_size / sizeof(LLCG_CommonRouteTableType));

    return 0;
}

/**
 * vcan_cb_set_route_table
 * @brief: SW4核下发filter和路由表的对应信息，SW0核负责解析并保存一份vcan_filter_route_table_map对应关系到本地
 * 
 * @TODO: 这里的filter_id实际上是hwobject_id，需要重命名
*/
static int vcan_cb_set_route_table(uint32_t param) {
    LLCG_COMMAND_PARAM_SET_ROUTE_TABLE *converted_param = (LLCG_COMMAND_PARAM_SET_ROUTE_TABLE*)param;
    uint32_t can_controller_id = converted_param->can_controller_id;
    uint32_t filter_id = converted_param->filter_id;
    LLCG_RouteTableBaseType *fast_route_table_ptr = (LLCG_RouteTableBaseType*)converted_param->fast_route_table_ptr;
    LLCG_RouteTableBaseType *common_route_table_ptr = (LLCG_RouteTableBaseType*)converted_param->common_route_table_ptr;

    if ((fast_route_table_ptr != NULL) && (common_route_table_ptr != NULL)) {
        hprintf(DEBUG, "error: fast_route_table_ptr and common_route_table_ptr are both NOT NULL\n");
        return -1;
    }

    if ((fast_route_table_ptr == NULL) && (common_route_table_ptr == NULL)) {
        hprintf(DEBUG, "error: fast_route_table_ptr and common_route_table_ptr are both NULL\n");
        return -1;
    }

    if (fast_route_table_ptr != NULL) {
        //计算SW4下发的路由表的index，然后指向自己本地的路由表
        uint8_t index = (((LLCG_RouteTableBaseType*)fast_route_table_ptr) - origin_base_route_ptr);
        can_filter_fast_route_set(can_controller_id, filter_id, index);
    }
    else {
        can_filter_common_route_set(can_controller_id, filter_id);
    }

    return 0;
}

/**
 * @brief SW0核收到其他核的send消息，让SW0核发送CAN消息
*/
void vcan_send(const switch0_can_gateway_UInt8Array128_t *x2can_raw,
				const uint64_t context, const ext_info_t *info)
{
    X2CAN * x2can = (X2CAN*)x2can_raw;
    X2CAN_PARAMS * x2can_param = &(x2can->param);
    uint32 cs;
    sint32 ret;

    hprintf(DEBUG, "enter vcan_cb_send_data bus:%d id:%d dlc:%d data:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
        x2can_param->des_can_bus_id, x2can->id, x2can->dlc,
        x2can->data[0], x2can->data[1], x2can->data[2], x2can->data[3],
        x2can->data[4], x2can->data[5], x2can->data[6], x2can->data[7]);

    cs = CAN_BUILD_CS_ATTR(x2can->dlc, x2can->rtr, x2can->ide, x2can->srr, x2can->esi, x2can->brs, x2can->edl);

    ret = can_output_queue_send(x2can_param->des_can_bus_id, x2can->id, cs, x2can->data,
                                FlexCAN_ComputePayloadSize(x2can->dlc));
    if (ret) {
        hprintf(DEBUG, "error: send tx bus:%u msg failed,\n", x2can_param->des_can_bus_id);
    }


    can_s_server->switch0_can_gateway_server.reply_can_gateway_send(
            SWITCH0_CAN_GATEWAY_NO_ERROR, context);
}
/**
 * @brief SW0核收到其他核的订阅消息，
 *        当SW0核收到了CAN数据后，要给这些核发送broadcast通知
*/
int32_t vcan_read_subcribed(uint8_t pid, uint8_t fid, uint8_t sid)
{
    int des_id = utils_get_destination_id_by_ipc_cpu_id(pid);
    hprintf(DEBUG, "enter vcan_read_subcribed pid:%d desid:%d\n", pid, des_id);
    if(des_id < 0) {
        hprintf(DEBUG, "utils_get_destination_id_by_ipc_cpu_id error, pid:%d\n",pid);
        return -1;
    }

    vcan_subcribed[des_id] = 1;
    vcan_subcribed_info[des_id].pid = pid;
    vcan_subcribed_info[des_id].fid = fid;
    vcan_subcribed_info[des_id].sid = sid;

    return 0;
}

boolean vcan_check_subcribed(uint8_t des_id) {

    if(vcan_subcribed[des_id] == 1)
        return true;
    else
        return false;
}

broadcast_reg_entry_t* vcan_get_subcribed_info(uint8_t des_id) {
    if(vcan_subcribed_info[des_id].pid == 0)
        return NULL;
    

    return &(vcan_subcribed_info[des_id]);
}

/**
 * @brief SW0核收到其他核的取消订阅消息，
 *        当SW0核收到了CAN数据后，取消给这些核发送broadcast通知
*/
int32_t vcan_read_unsubcribed(uint8_t pid, uint8_t fid, uint8_t sid)
{
    return -1;
}

#ifdef USERSPACE
#include <fcntl.h> // O_RDWR O_SYNC
#include <sys/mman.h> // PROT_READ PROT_WRITE MAP_SHARED
#endif

#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int pkt_hex_dump(unsigned char *buffer, int len) {
    int rowsize = 16;
    int remaining = len;
    uint8_t *data; 

#ifdef USERSPACE
    int fd;
    void *map_base; 

    if (len > 4096) {
        printf("error len:%d > 4096, due mmap can only map 4K byte once, len can not over 4096, please call this funciont multi time\n", len);
        return -1;
    }
    if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
        printf("open /dev/mem error ret:%d\n", fd);
        return -1;
    }
    
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (uint64_t)buffer & ~MAP_MASK);
    data = map_base;

#else
    data = (uint8_t *)buffer;
#endif

    hprintf(DEBUG, "Packet hex dump:0x%x \n", data);

    for (int i = 0; i < len; i += rowsize) {
        int linelen = MIN(remaining, rowsize);
        remaining -= rowsize;

        if (linelen == rowsize) {
            hprintf(DEBUG, "%06x \t %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X\n",
                i,
                data[0],  data[1],  data[2],  data[3],
                data[4],  data[5],  data[6],  data[7],
                data[8],  data[9],  data[10], data[11],
                data[12], data[13], data[14], data[15]);
        } else {
            char last_line_str[128] = {0};
            char *last_line_str_p = last_line_str;

            sprintf(last_line_str_p, "%06x \t", i);
            last_line_str_p += 8;
            for (int l = 0; l < linelen; ++l) {
                sprintf(last_line_str_p, " %02X", data[l]);
                last_line_str_p += 3;
                //每4个加个空格
                if ((l + 1) % 4 == 0) {
                    *last_line_str_p = ' ';
                    last_line_str_p += 1;
                }
            }
            last_line_str_p[0] = '\n';
            hprintf(DEBUG, "%s", last_line_str);
        }
        data += linelen;
    }

#ifdef USERSPACE
    munmap(map_base, MAP_SIZE);
    close(fd);
#endif

    return 0;
}
